﻿using System.Dynamic;
using System.Globalization;
using System.ComponentModel;
using System.Timers;
using System.Threading;
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;

public class MovementPlayer : MonoBehaviour
{
    public GameObject endScreen;
    public bool hasEnded;

    public float runSpeed;
    public float jumpForce;
    [Range(0,1)]
    public int dJumpLimit = 1;
    public bool isGrounded;
    private bool canMove = true;
    private float moveInput;

    private Rigidbody2D myBody;
    private Rigidbody2D rigidbody2d;
    
    public Transform groundCheck;
    public LayerMask groundLayer;
    public Vector3 range;

    private bool facingRight = true;

    [Header("Dashing")]
    public bool canDash = true;
    public float dashingTime;
    public float dashSpeed;
    public float dashJumpIncrease;
    public float timeBtwDashes;

    [Header("Movement nullifier")]
    public bool multiInput = false;

    [Header("Wallrunning Vars")]
    public int wallRunSpeed = 20;
    public float wallRunTime = 1;
    public float wallRunTimeEnd = 1;
    public bool isTouchingWall;
    public bool isWallRunning = false;
    public Vector3 wallCheckRange;

    public Transform wallCheck;
    public LayerMask wallLayer;

    private Animator anim;

    [Header("Respawn trigger")]

    public Transform spawnpoint;
    public Transform lavaCheck;
    public bool isTouchingLava = false;
    public Vector3 lavaCheckRange;
    public LayerMask lavaLayer;

    [Header("Game end trigger")]

    public Transform endCheck;
    public bool isTouchingEnd = false;
    public Vector3 endCheckRange;
    public LayerMask endLayer;

    
    void Start()
    {
        anim = GetComponent<Animator>();

        // Start the game without the end screen; keep for later
        endScreen.SetActive(false);
        
    }
    
    void Awake()
    {
        myBody = GetComponent<Rigidbody2D>();
        rigidbody2d = transform.GetComponent<Rigidbody2D>();
    }

    void Update()
    {
        CheckCollisionForJump();
        MovementNullifier();
        wallRunning();
        Respawn();
        
    }

    void FixedUpdate()
    {
        endGamer();
        CharMovement();

        // On the conidition that the player has at least 5 potions, they may dash and superjump
        if(canMove && isGrounded && ScoreCounter.potionAmount >= 5)
        {
            if(Input.GetKeyDown(KeyCode.LeftShift))
            {
                DashAbility();
            }
        }
        
    }

    void CharMovement()
    {
        moveInput = Input.GetAxis("Horizontal") * runSpeed;

        // this will allow other variables to activate based on whether there is movement or not.
        if(canMove == true)
        {
            myBody.velocity = new Vector2(moveInput, myBody.velocity.y);
            
            if(runSpeed > 0)
            {
                anim.SetBool("isRunning", true);
            }
        }

        if(Input.GetAxis("Horizontal") == 0 && isGrounded)
        {
            anim.SetBool("isRunning", false);
        }

        if(moveInput > 0 && !facingRight || moveInput < 0 && facingRight)
            Flip();
    }

    private void OnDrawGizmosSelected() 
    {
        // Player Ground collision cube
        Gizmos.color = Color.black;
        Gizmos.DrawWireCube(groundCheck.position, range);

        // Player Wall collision cube
        Gizmos.color = Color.blue;
        Gizmos.DrawWireCube(wallCheck.position, wallCheckRange);

        // Player lava collision cube
        Gizmos.color = Color.yellow;
        Gizmos.DrawWireCube(lavaCheck.position, lavaCheckRange);

        // Player end collision cube
        Gizmos.color = Color.red;
        Gizmos.DrawWireCube(endCheck.position, endCheckRange);
    }

    // Fullhop
    void CheckCollisionForJump()
    {
        isGrounded = Physics2D.OverlapBox(groundCheck.position, range, 0, groundLayer);

        //Allow double jumping + regular jumping
        if(Input.GetKeyDown("space") && dJumpLimit > 0)
        {
            rigidbody2d.velocity = Vector2.up * jumpForce;
            dJumpLimit--;
            anim.SetTrigger("jumpTrigger");
        }
        //
        else if(Input.GetKeyDown("space") && dJumpLimit == 0 && isGrounded == true)
        {
           rigidbody2d.velocity = Vector2.up * jumpForce; 
        }

        if(isGrounded == true)
        {
            dJumpLimit = 1;
            anim.SetBool("isJumping", false);
        }
        else
        {
            anim.SetBool("isJumping", true);
        }
        
    }

    void Flip()
    {
        facingRight = !facingRight;

        Vector3 transformScale = transform.localScale;
        transformScale.x *= -1;
        transform.localScale = transformScale;

    }
    
    void DashAbility()
    {
        if(canDash)
        {
            StartCoroutine(Dash());
        }
    }
    // Initiate dash, increase jump height and disable double jumping.
    IEnumerator Dash()
    {
        canDash = false;
        runSpeed = dashSpeed;
        jumpForce = dashJumpIncrease;
        yield return new WaitForSeconds(dashingTime);
        dJumpLimit = 0;
        runSpeed = 10;
        jumpForce = 9f;
        yield return new WaitForSeconds(timeBtwDashes);
        canDash = true;
    }

    void MovementNullifier()
    {
        if(Input.GetKey(KeyCode.A) && Input.GetKey(KeyCode.D))
        {
            multiInput = true;
            runSpeed = 0;
            anim.SetBool("isRunning", false);
        }

        if(multiInput == true && (Input.GetKey(KeyCode.D) == false || Input.GetKey(KeyCode.A) == false))
            {
                runSpeed = 10;
                multiInput = false;
            }
        
    }

    void wallRunning()
    {
        isTouchingWall = Physics2D.OverlapBox(wallCheck.position, wallCheckRange, 0, wallLayer);
        
        //if I am not on the ground, and I am running towards the wall,
        // initiate wallRun sequence
        // once sequence initiates, disable the ability to wallrun again until I touch the GroundLayer.

        if(isGrounded == false && isTouchingWall == true && rigidbody2d.velocity.y > 0 && ScoreCounter.potionAmount >= 2)
        {
            isWallRunning = true;
            wallRunTime += Time.deltaTime;
        }
        else
        {
            isWallRunning = false;
            wallRunTime = 0;
            anim.SetBool("isRunningWall", false);
        }

        if(isWallRunning == true && wallRunTime < wallRunTimeEnd)
        {
            rigidbody2d.velocity = new Vector2(rigidbody2d.velocity.x, wallRunSpeed);
            anim.SetBool("isRunningWall", true);
        }
    }
    
    void Respawn()
    {
       // Use wallCheck hitbox to check collision with lava
       isTouchingLava = Physics2D.OverlapBox(lavaCheck.position, lavaCheckRange, 0, lavaLayer);
       
       if(isGrounded == false && isTouchingLava == true)
       {
           // teleport player to the set spawn point
           this.transform.position = spawnpoint.position;
       }
    }

    void endGamer()
    {
        isTouchingEnd = Physics2D.OverlapBox(endCheck.position, endCheckRange, 0, endLayer);

        // End the game once the player reaches the trapdoor
        if(isGrounded == true && isTouchingEnd == true)
        {
            Time.timeScale = 0f;
            endScreen.SetActive(true);
            hasEnded = true;
        }
    }
}